using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Demo
{
    public static class ApplicationBuilderExtension{

        internal const string InvokeMethodName = "Invoke";
        internal const string InvokeAsyncMethodName = "InvokeAsync";

        public static IApplicationBuilder Use(this IApplicationBuilder builder,Func<RequestContext,RequestDelegate,Task> func){
             Func<RequestDelegate, RequestDelegate> middleware = (next) =>
             {
                 return new RequestDelegate((context) =>
                 {
                     return func(context,next);
                 });
             };
            builder.Use(middleware);
            return builder;
        }
        
        public static IApplicationBuilder UseMiddleware<T>(this IApplicationBuilder builder, params object[] args)
        {
            var middleware=typeof(T);
            builder.Use((next)=>{
                var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                var invokeMethods = methods.Where(m =>
                    string.Equals(m.Name, InvokeMethodName, StringComparison.Ordinal)
                    || string.Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal)
                    ).ToArray();
                if (invokeMethods.Length > 1)
                {
                    throw new InvalidOperationException(InvokeMethodName);
                }

                if (invokeMethods.Length == 0)
                {
                    throw new InvalidOperationException(InvokeMethodName);
                }

                var methodinfo = invokeMethods[0];
                if (!typeof(Task).IsAssignableFrom(methodinfo.ReturnType))
                {
                    throw new InvalidOperationException("返回值不是Task类型");
                }

                var parameters = methodinfo.GetParameters();
                if (parameters.Length == 0 || parameters[0].ParameterType != typeof(RequestContext))
                {
                    throw new InvalidOperationException("参数不正确");
                }
                var ctorArgs = new object[args.Length + 1];
                ctorArgs[0] = next;
                Array.Copy(args, 0, ctorArgs, 1, args.Length);
                
                var instance=Activator.CreateInstance(middleware,ctorArgs);
                //HttpAbstraction的写法
                //var instance = ActivatorUtilities.CreateInstance(builder.ApplicationServices, middleware, ctorArgs);
                if (null==instance)
                {
                    throw new InvalidOperationException("参数异常");
                }
                return (RequestDelegate)methodinfo.CreateDelegate(typeof(RequestDelegate), instance);
            });
            return builder;
        }


        public static void Run(this IApplicationBuilder builder,Func<RequestContext,Task> last)
        {
            Func<RequestDelegate, RequestDelegate> middleware = (next) =>
            {
                  return new RequestDelegate(last);
            };
            builder.Use(middleware);
        }
    }
}

